/************************************************************************
  Scheme interpreter
  
  Copyright (C) 2010 Marioly Garza 

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Lesser General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.
  
  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.
  
  You should have received a copy of the GNU Lesser General Public
  License along with this program. If not, see
  <http://www.gnu.org/licenses/>.

************************************************************************/

#include "parser.h"

object* parser::parse(std::string exp)
{
    std::queue<object*> tokens = lexer::tokenize(exp);
    std::stack<object*> stack;

    if (tokens.size() > 0)
        stack.push(sexp(tokens));

    if (stack.size() == 1)
    {
        return stack.top();
    }
    else
    {
        throw scheme_exception("empty stack");
    }
}

object* parser::sexp(std::queue<object*> &tokens)
{
    object* o = tokens.front();
    if (tokens.size() == 0)
    {
        return NULL;
    }
    else if (util::is<sstring>(o) && *((sstring*)o) == "\"")
    {
        tokens.pop();
        sstring* nx = (sstring*)tokens.front();
        tokens.pop();
        std::string ss = "";
        while (tokens.size() > 0 && *nx != "\"") {
            ss += (!ss.empty() ? " " : "") + ((std::string)*nx);
            nx = (sstring*)tokens.front();
            tokens.pop();
        }
        if (*nx != "\"")
            throw scheme_exception("unterminated string constant");

        return new sstring("\"" + ss + "\"");
    }
    else if (util::is<sstring>(o) && *((sstring*)o) == "(")
    {
        tokens.pop();
        return parser::next_list(tokens);
    }
    else if (util::is<sstring>(o) && *((sstring*)o) == "'")
    {
        tokens.pop();
        return new pair(new sstring("quote"), (pair*)sexp(tokens));
    }
    else
    {
        tokens.pop();
        return o;
    }
}

object* parser::next_list(std::queue<object*> &tokens)
{
    object *cur = sexp(tokens);

    pair *p = NULL, *pt = NULL;
    while (tokens.size() > 0 && cur != NULL && *((sstring*)cur) != ")")
    {
        if (p == NULL)
        {
            p = new pair(cur, NULL);
            pt = p;
        }
        else
        {
            pt->cdr = new pair(cur, NULL);
            pt = pt->cdr;
        }
        cur = sexp(tokens);
    }

    return p;
}

